﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Djs.Tools.ProcesExplorer
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
            this._InitForm();
        }
        private void MainForm_Load(object sender, EventArgs e)
        {
        }
        private void MainForm_Shown(object sender, EventArgs e)
        {
            this._LoadProcesses();
        }
        private void _RefreshTb_Click(object sender, EventArgs e)
        {
            this._LoadProcesses();
        }
        private void _InitForm()
        {
            this._ProcessList.View = View.Details;
            this._ProcessList.MultiSelect = false;
            this._ProcessList.FullRowSelect = true;
            this._ProcessList.GridLines = false;

            this._ProcessList.Items.Clear();
            this._ProcessList.Groups.Clear();
            this._ProcessList.Columns.Clear();
            this._ProcessList.Columns.Add(new ColumnHeader() { Name = "ProcessNameCol", Text = "Process", TextAlign = HorizontalAlignment.Center, Width = this._ProcessList.Width });
            this._ProcessList.SelectedIndexChanged += new EventHandler(_ProcessList_SelectedIndexChanged);

            this._SetReadOnly(this._PNameTxt);
            this._SetReadOnly(this._PFileNameTxt);
            this._SetReadOnly(this._PArgumentsTxt);
            this._SetReadOnly(this._PStartTimeTxt);
            this._SetReadOnly(this._PStartOffsetTxt);
        }
        private void _SetReadOnly(TextBox textBox)
        {
            textBox.ReadOnly = true;
            textBox.BackColor = SystemColors.Info;
            textBox.ForeColor = SystemColors.InfoText;
        }
        private void _ProcessList_SelectedIndexChanged(object sender, EventArgs e)
        {
            ListViewItem item = ((this._ProcessList.SelectedItems.Count == 0) ? null : this._ProcessList.SelectedItems[0]);
            ProcessInfo info = (item == null ? null : item.Tag as ProcessInfo);
            this.ShowProcessData(info);
        }
        private void _LoadProcesses()
        {
            this._LoadProcesses(false, null);
        }
        private void _LoadProcesses(bool silent)
        {
            this._LoadProcesses(silent, null);
        }
        private void _LoadProcesses(bool silent, string waitLabel)
        {
            if (this._BackThread != null) return;

            if (!silent)
            {
                this._ProcessList.Visible = false;
                this._RefreshTb.Enabled = false;
                this._WaitLabel.Text = (String.IsNullOrEmpty(waitLabel) ? "Please wait, loading process list..." : waitLabel);
                this._WaitLabel.Visible = true;
            }

            this._BackThread = new System.Threading.Thread(this._LoadProcessesBackground);
            this._BackThread.Name = "BackThread";
            this._BackThread.IsBackground = true;
            this._BackThread.Start();
        }
        private List<ProcessInfo> _ProcessInfoList;
        private System.Threading.Thread _BackThread;
        private void _LoadProcessesBackground()
        {
            Dictionary <int, string> infoDict = new Dictionary<int,string>();
            string querry = "SELECT ProcessId, CommandLine FROM Win32_Process";
            // querry = "SELECT * FROM Win32_Process";           načte všechny sloupce, nám stačí ProcessId, CommandLine
            using (System.Management.ManagementObjectSearcher searcher = new System.Management.ManagementObjectSearcher(querry))    // WHERE ProcessId = " + this.Id.ToString()))
            {
                System.Management.ManagementObjectCollection c = searcher.Get();
                foreach (System.Management.ManagementObject o in c)
                {
                    // string xx2 = o.GetText(System.Management.TextFormat.Mof);
                    object idc = o["ProcessId"];
                    int id = Convert.ToInt32(idc);
                    string cmd = (string)o["CommandLine"];
                    infoDict.Add(id, cmd); ;
                }
            }


            System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcesses();
            List<ProcessInfo> processInfoList = new List<ProcessInfo>();
            foreach (System.Diagnostics.Process process in processes)
            {
                string cmdLine;
                infoDict.TryGetValue(process.Id, out cmdLine);
                ProcessInfo info = new ProcessInfo(process, cmdLine);
                processInfoList.Add(info);

                //info.CreateAfter +=new EventHandler(info_CreateAfter1);
                //info.CreateAfter +=new EventHandler(info_CreateAfter2);
                //info.OnCreateAfter();
            }

            processInfoList.Sort(ProcessInfo.CompareByName);
            this._ProcessInfoList = processInfoList;

            this.BeginInvoke(new Action(this._LoadProcessesDone));

            this._BackThread = null;
        }
        private void _LoadProcessesDone()
        {
            this._ProcessList.Items.Clear();
            List<ProcessInfo> processInfoList = this._ProcessInfoList;
            foreach (ProcessInfo info in processInfoList)
            {
                ListViewItem item = new ListViewItem(info.Title);
                item.Tag = info;
                this._ProcessList.Items.Add(item);
            }

            this._ProcessList.Visible = true;
            this._ProcessList.Refresh();
            this._WaitLabel.Visible = false;
            this._RefreshTb.Enabled = true;
        }
        private void info_CreateAfter1(object sender, EventArgs e) { }
        private void info_CreateAfter2(object sender, EventArgs e) { }
        private void ShowProcessData(ProcessInfo info)
        {
            bool clear = (info == null);
            this._PNameTxt.Text = (clear ? "" : info.ProcessName);
            this._KillProcess.Enabled = (clear ? false : (info.Id > 0));
            this._PFileNameTxt.Text = (clear ? "" : info.FileName);
            this._HelpBtn.Enabled = (clear ? false : (!String.IsNullOrEmpty(info.FileName)));
            this._PArgumentsTxt.Text = (clear ? "" : info.CommandLine);
            this._PStartTimeTxt.Text = (clear ? "" : info.StartTime.ToString());
            this._PStartOffsetTxt.Text = (clear ? "" : info.StartAfterOs.ToString());

            this._CurrentProcess = info;
        }
        private ProcessInfo _CurrentProcess;
        private void _HelpBtn_Click(object sender, EventArgs e)
        {
            if (this._CurrentProcess == null) return;
            string file = System.IO.Path.GetFileName(this._CurrentProcess.FileName);
            if (String.IsNullOrEmpty(file)) return;

            string wcmd = "http://www.google.cz/#q=" + file;
            System.Diagnostics.Process.Start(wcmd);
        }
        private void _KillProcess_Click(object sender, EventArgs e)
        {
            if (this._CurrentProcess == null) return;
            try
            {
                System.Diagnostics.Process process = System.Diagnostics.Process.GetProcessById(this._CurrentProcess.Id);
                if (process == null) return;
                process.Kill();
                this._LoadProcesses(false, "OK, process was killed. Reloading...");
            }
            catch (Exception exc)
            {
                _ShowError(exc.Message);
                this._LoadProcesses(true);
            }
        }
        private void _ShowError(string message)
        {
            MessageBox.Show(this, message, "ProcessExplorer Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }
    internal class ProcessInfo
    {
        internal ProcessInfo(System.Diagnostics.Process process, string cmdLine)
        {
            this._Process = process;
            try { this._MainModule = process.MainModule; } catch { }
            try { this._StartInfo = process.StartInfo; } catch { }


            this.Id = process.Id;
            this.ProcessName = process.ProcessName;
            this.HasWindow = (process.MainWindowHandle.ToInt32() != 0);
            this.Responding = process.Responding;

            this.Title = process.MainWindowTitle;
            if (String.IsNullOrEmpty(this.Title))
                this.Title = process.ProcessName;

            if (this._MainModule != null)
            {
                this.FileName = this._MainModule.FileName;
                this.ModuleName = this._MainModule.ModuleName;
                this.StartTime = this._Process.StartTime;

                DateTime osStarted = DateTime.Now.AddMilliseconds(-Environment.TickCount);
                if (this.StartTime.Year > 1000)
                    this.StartAfterOs = this.StartTime - osStarted;
            }

            if (this._StartInfo != null)
            {
                // this.CommandLine = this._StartInfo.Arguments;          To nemá význam, protože _StartInfo.Arguments je vždy Empty, viz Google (? processstartinfo.arguments empty), proto použijeme System.Management.ManagementObjectSearcher.
                var un = this._StartInfo.UserName;

            }

            this.CommandLine = cmdLine;
            //try
            //{
            //    using (System.Management.ManagementObjectSearcher searcher = new System.Management.ManagementObjectSearcher("SELECT CommandLine FROM Win32_Process WHERE ProcessId = " + this.Id.ToString()))
            //    {
            //        this.CommandLine = "";
            //        foreach (System.Management.ManagementObject o in searcher.Get())
            //        {
            //            this.CommandLine = (this.CommandLine.Length == 0 ? "" : Environment.NewLine) + (string)o["CommandLine"];
            //        }
            //    }
            //}
            //catch { }

            this.GroupName = (this.HasWindow ? "Applications" : "Services");
        }
        private System.Diagnostics.Process _Process;
        private System.Diagnostics.ProcessModule _MainModule;
        private System.Diagnostics.ProcessStartInfo _StartInfo;
        internal string Title { get; private set; }
        internal int Id { get; private set; }
        internal string ProcessName { get; private set; }
        internal bool HasWindow { get; private set; }
        internal bool Responding { get; private set; }
        internal string FileName { get; private set; }
        internal string ModuleName { get; private set; }
        internal string CommandLine { get; private set; }
        internal DateTime StartTime { get; private set; }
        internal TimeSpan StartAfterOs { get; private set; }
        internal string GroupName { get; private set; }
        internal static int CompareByName(ProcessInfo a, ProcessInfo b)
        {
            if (a == null && b == null) return 0;
            if (a == null) return -1;
            if (b == null) return 1;

            return a.Title.CompareTo(b.Title);
        }
    }
}
